package UsedCar;

import java.awt.Color;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.List;

import org.ahmadsoft.arrays.FasterArrayList;
import org.apache.commons.lang.StringUtils;

import uchicago.src.sim.gui.Drawable;
import uchicago.src.sim.gui.SimGraphics;
import uchicago.src.sim.space.Object2DTorus;
import uchicago.src.sim.util.Random;

/**
 * @author August F.Y. Chao
 * 
 */
public abstract class Agent implements Drawable {

	public static final boolean FLAG = Model.FLAG;
	/**
	 * @param PERSON_EVAL_OPTIMISM
	 *            樂觀 0
	 * @param PERSON_EVAL_PESSMISTIC
	 *            悲觀 1
	 * @param PERSON_EVAL_NEUTRAL
	 *            中性 2
	 */
	public static final int PERSON_EVAL_OPTIMISM = 0,
			PERSON_EVAL_PESSMISTIC = 1, PERSON_EVAL_NEUTRAL = 2;

	/**
	 * @param space
	 *            買賣空間
	 */
	protected Object2DTorus space;
	/**
	 * @param sellerS
	 *            賣家空間
	 */
	protected Object2DTorus sellerS;
	/**
	 * @param myX
	 *            我的位置 X
	 */
	private int myX;
	/**
	 * @param myY
	 *            我的位置 Y
	 */
	private int myY;
	/**
	 * @param myColor
	 *            我的顏色
	 */
	private Color myColor = Color.blue;
	/**
	 * @param myKnows
	 *            我的知識
	 */
	protected String[] myKnows;
	/**
	 * @param knowsM
	 *            知識市場
	 */
	protected Knowledges knowsM;
	/**
	 * @param initKnowR
	 *            開始的知識比例
	 */
	public float initKnowR;
	/**
	 * @param role
	 *            角色
	 */
	public String role = "N";
	/**
	 * @param frm
	 *            知識庫存
	 */
	public Forum frm;
	/**
	 * @param knowsShareR
	 *            單次分享知識的比例
	 */
	protected float knowsShareR = (float) 0.3;
	/**
	 * @param maxPostNum
	 *            最大貼文數
	 */
	protected int maxPostNum = 1;
	/**
	 * @param maxReadNum
	 *            最大看文數
	 */
	protected int maxReadNum = 1;
	/**
	 * @param person_Eval
	 *            個人在評價時，猜"Y"的程度。0 樂觀、1 悲觀、2 平平
	 */
	protected int person_Eval;
	/**
	 * @param yr
	 *            我的年紀
	 */
	protected int yr = 0;
	/**
	 * @param carL
	 *            我的車庫
	 */
	protected FasterArrayList<Car> carL = new FasterArrayList<Car>();
	/**
	 * @param carLByPrice
	 *            依車子的價格排列的表
	 */
	protected Hashtable<Integer, List<Car>> carLByPrice = new Hashtable<Integer, List<Car>>();

	/**
	 * @param qual
	 *            品質模式
	 */
	protected Quality qual = null;
	/**
	 * @param inInflu
	 *            是否進行影響
	 */
	protected boolean isInflu = false;

	/**
	 * @param MAX_KM_EFFER
	 *            最大知識分享的工作比例
	 */
	// protected int MAX_KM_EFFER = 100;

	/**
	 * @param myKmEffer
	 *            自己目前的知識分享工作總量
	 */
	// protected int myKmEffer = 0;

	/**
	 * @param imp
	 *            對其它人的印象資料
	 */
	public Impression imp = new Impression();

	/**
	 * 建構子
	 * 
	 * @param space
	 *            交易平台
	 * @param knows
	 *            知識市場
	 * @param frm
	 *            知識庫存
	 * @param qual
	 *            車子的品質模式
	 * @param isInfluence
	 *            是否進行影響計算
	 * @param eval
	 *            估價的 0 樂觀、1 悲觀、2 平平
	 */
	public Agent(Object2DTorus sellerS, Object2DTorus space, Forum frm,
			Quality qual, Knowledges knowsM, boolean isInfluence, int eval) {

		// 產生亂數種子
		long s = System.currentTimeMillis();
		Random.setSeed(s);

		// 設定個人估價參數
		this.setPerson_Eval(eval);

		// 設定空間
		this.setSellerS(sellerS);
		this.setSpace(space);
		this.qual = qual;
		this.isInflu = isInfluence;
		this.placeAgent();
		this.setknowsM(knowsM);

		// 設定知識的庫存
		this.setFrm(frm);
	}

	/**
	 * 產生 Agent 的知識
	 */
	protected void initKnows() {
		this.setMyknows(this.knowsM.getRoleKnows(this.getInitKnowR()));
	}

	/**
	 * 列出知識
	 */
	protected void listMyKnows() {
		String foo = "[" + this.getRole() + "]: "
				+ StringUtils.join(this.myKnows, " | ");

		System.out.println(foo);
	}

	/**
	 * 將 agent 放到平面中
	 */
	protected void placeAgent() {

		// 放到平面中
		do {
			Random.createUniform();

			myX = Random.uniform.nextIntFromTo(0, space.getSizeX() - 1);
			myY = Random.uniform.nextIntFromTo(0, space.getSizeY() - 1);
		} while (space.getObjectAt(myX, myY) != null);
		space.putObjectAt(myX, myY, this);
	}

	/**
	 * 將文章加入論壇中
	 * 
	 * @param art
	 *            文章本文
	 */
	public void add2Forum(Post art) {
		this.frm.addPost(art);
	}

	/**
	 * 依 Agent 的鑑價水準進行評估一輛車子的價格
	 * 
	 * @param genCar
	 *            產生的汽車
	 */
	public float evaluate(Car genCar) {
		String[] allQuals = genCar.qal.getQualList(genCar.getCarType());
		String[] quals = genCar.getQuals();

		int evalPrice = 1;

		for (int i = 0; i < quals.length; i++) {

			String[] qNeed = genCar.qal.getKnows(quals[i]);

			float IhaveKnowNum = 0;
			for (int idx = 0; idx < qNeed.length; idx++) {
				if (this.knowsM.in_array(myKnows, qNeed[idx])) {
					IhaveKnowNum += 1;
				}
			}
			float howKnow = IhaveKnowNum / qNeed.length;

			if (howKnow == 1) {
				evalPrice += genCar.qal.getPrice(allQuals[i]);
			} else {
				switch (this.person_Eval) {
				// 樂觀
				case PERSON_EVAL_OPTIMISM:
					// 不管怎樣，就是猜 有
					evalPrice += genCar.qal.getPrice(allQuals[i]);
					break;
				// 悲觀
				case PERSON_EVAL_PESSMISTIC:
					// 不管怎樣，就是猜 -沒有- 100
					evalPrice += 100;
					break;
				// 中性
				case PERSON_EVAL_NEUTRAL:
					// 了解多少猜多少
					evalPrice += genCar.qal.getPrice(allQuals[i]) * howKnow;
					break;
				}
			}
		}
		return (float) (evalPrice * (1 - genCar.yr * genCar.DEPERCIATION_RATE));
	}

	// public int evaluateOLD(Car genCar) {
	// String[] quals = genCar.getQuals();
	//
	// int evalPrice = 0;
	//
	// for (int i = 0; i < quals.length; i++) {
	// String[] qNeed = genCar.qal.getKnows(quals[i]);
	// float howKnow = getHowKnow(qNeed);
	//
	// if (howKnow == 1) {
	// evalPrice += genCar.qal.getPrice(quals[i]);
	// } else {
	// switch (this.person_Eval) {
	// // 樂觀
	// case PERSON_EVAL_OPTIMISM:
	// // 不管怎樣，就是猜 有
	// evalPrice += genCar.qal.getPrice(quals[i]);
	// break;
	// // 悲觀
	// case PERSON_EVAL_PESSMISTIC:
	// // 不管怎樣，就是猜 沒有
	// evalPrice += 0;
	// break;
	// // 中性
	// case PERSON_EVAL_NEUTRAL:
	// // 了解多少猜多少
	// evalPrice += genCar.qal.getPrice(quals[i]) * howKnow;
	// break;
	// }
	// }
	// }
	// return evalPrice;
	// }

	public float getHowKnow(String[] qNeed) {

		String[] diff = inMyKnows(qNeed);

		// System.out.println("CAR: " + this.knowsM.listKnows(qNeed));
		// System.out.println("ME: " + this.knowsM.listKnows(this.myKnows));
		// System.out.println("DUP: " + this.knowsM.listKnows(diff));
		return (float) diff.length / (float) this.knowsM.knowNum;
	}

	/**
	 * @param need
	 *            需要的知識
	 * @return 兩者間的交集
	 */
	protected String[] inMyKnows(String[] need) {
		FasterArrayList<String> rKnows = new FasterArrayList<String>();

		for (int i = 0; i < need.length; i++) {
			for (int j = 0; j < myKnows.length; j++) {
				if (need[i].equals(myKnows[j])) {
					rKnows.add(need[i]);
				}
			}
		}

		return rKnows.toArray(new String[rKnows.size()]);
	}

	/**
	 * 我不知道的知識
	 * 
	 * @param chk
	 *            待查的知識
	 * @return 我沒有的知識串
	 */
	protected String[] iDontKnow(String[] chk) {
		long time = System.currentTimeMillis();

		List<String> diffList = new FasterArrayList<String>(Arrays.asList(chk));
		for (String s : myKnows) {
			if (diffList.contains(s)) {
				diffList.remove(s);
			}
		}

		if (FLAG) {
			time = System.currentTimeMillis() - time;
			if (time > 5) {
				// if (diffList.size() > 0) {
				// System.out.println("CHK = " + this.knowsM.listKnows(chk));
				// System.out.println("KNW = "
				// + this.knowsM.listKnows(myKnows));
				// System.out.println("Diff = "
				// + this.knowsM.listKnows(diffList
				// .toArray(new String[diffList.size()])));
				// }
				System.out.println("(" + getRole() + ") iDontKnow: " + time);
			}
		}
		return diffList.toArray(new String[diffList.size()]);
	}

	/**
	 * 送車到車庫
	 * 
	 * @param newCar
	 *            新車
	 */
	public void addCar(Car newCar) {

		// 加上所有人
		newCar.owner = (Agent) this;

		// 加到車庫中
		this.carL.add(newCar);

		// 將車依價格放好(加快運算)
		List<Car> rCar = new FasterArrayList<Car>();
		if (carLByPrice.containsKey(newCar.getEvaledPrice())) {
			rCar = (List<Car>) carLByPrice.get(newCar.getEvaledPrice());
		}
		rCar.add(newCar);
		carLByPrice.put((int) newCar.getEvaledPrice(), rCar);
	}

	/**
	 * 取得車子數
	 * 
	 * @return 車數
	 */
	public int getCarNum() {
		return this.carL.size();
	}

	/**
	 * 老一個tick
	 */
	public void doAging() {
		this.yr += 1;
	}

	/**
	 * @return 個人的估價方式
	 */
	public String getPE() {
		switch (person_Eval) {
		case PERSON_EVAL_NEUTRAL:
			return "=";
		case PERSON_EVAL_OPTIMISM:
			return "+";
		case PERSON_EVAL_PESSMISTIC:
			return "-";
		}
		return null;
	}

	public void doKM_T() {
		long time;

		if (FLAG) {
			time = System.currentTimeMillis();
		}
		doKM();
		if (FLAG) {
			time = System.currentTimeMillis() - time;
			if (time > 5) {
				System.out.println("(" + getRole() + ") in doKM_T(): " + time
						+ " ");
			}

		}

	}

	// ---------------------------------------------------------------------------------------------------------------------------------------------//
	// abstract functions
	// ---------------------------------------------------------------------------------------------------------------------------------------------//
	/**
	 * 進行分享知識
	 */
	public abstract void doKM();

	/**
	 * 設定參數
	 */
	public abstract void setVariables();

	// ---------------------------------------------------------------------------------------------------------------------------------------------//
	// Over-Rides
	// ---------------------------------------------------------------------------------------------------------------------------------------------//
	/**
	 * 產生圖形
	 */
	@Override
	public void draw(SimGraphics g) {
		g.setDrawingCoordinates(this.getX() * g.getCurWidth(),
				this.getY() * g.getCurHeight(), 0);

		g.drawFastRect(this.getMyColor());
	}

	@Override
	public int getX() {
		return this.myX;
	}

	@Override
	public int getY() {
		return this.myY;
	}

	// ---------------------------------------------------------------------------------------------------------------------------------------------//
	// 變數的 setter and getter
	// ---------------------------------------------------------------------------------------------------------------------------------------------//
	public Object2DTorus getSpace() {
		return space;
	}

	public void setSpace(Object2DTorus space) {
		this.space = space;
	}

	public int getMyX() {
		return myX;
	}

	public void setMyX(int myX) {
		this.myX = myX;
	}

	public int getMyY() {
		return myY;
	}

	public void setMyY(int myY) {
		this.myY = myY;
	}

	public Color getMyColor() {
		return myColor;
	}

	public void setMyColor(Color myColor) {
		this.myColor = myColor;
	}

	public String[] getMyknows() {
		return myKnows;
	}

	public void setMyknows(String[] myKnows) {
		this.myKnows = myKnows;
	}

	public Knowledges getknowsM() {
		return knowsM;
	}

	public void setknowsM(Knowledges knowsM) {
		this.knowsM = knowsM;
	}

	public float getInitKnowR() {
		return initKnowR;
	}

	public void setInitKnowR(float initKnowR) {
		this.initKnowR = initKnowR;
	}

	public String getRole() {
		return role;
	}

	public void setRole(String role) {
		this.role = role;
	}

	public Forum getFrm() {
		return frm;
	}

	public void setFrm(Forum frm) {
		this.frm = frm;
	}

	public float getKnowsShareR() {
		return knowsShareR;
	}

	public void setKnowsShareR(float knowsShareR) {
		this.knowsShareR = knowsShareR;
	}

	public int getMaxPostNum() {
		return maxPostNum;
	}

	public void setMaxPostNum(int maxPostNum) {
		this.maxPostNum = maxPostNum;
	}

	public int getPerson_Eval() {
		return person_Eval;
	}

	public void setPerson_Eval(int person_Eval) {
		this.person_Eval = person_Eval;
	}

	public int getYr() {
		return yr;
	}

	public void setYr(int yr) {
		this.yr = yr;
	}

	public Object2DTorus getSellerS() {
		return sellerS;
	}

	public void setSellerS(Object2DTorus sellerS) {
		this.sellerS = sellerS;
	}

}
